/**
**************************************************************************************
*Palisma - Secrets of the Illuminati is an open-source 2D RPG                        *
*Copyright (C) 2006, Tony Sparks                                                     *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once

#include "../shared/geom.h"
#include "../shared/vector.h"
#include "../shared/entdict.h"
#include "PhysicsObject.h"
#include "StateMachine.h"
#include "EntityController.h"

#include <string>
#include <map>

class IWeapon;
#include "Inventory.h"
/**
=============
Entity Flags 
=============
*/
enum {
    EF_UPDATE           = (1<<0),
    EF_NOTONSCREEN      = (1<<1),
    EF_MOVED            = (1<<2),
    
    /*-----------------------
        Weapon Flags
    ------------------------*/
    EF_WP_DRAWN         = (1<<3),
    EF_WP_ONGROUND      = (1<<4),

    EF_ATTACHED_TO_CAMERA = (1<<5),
    EF_NOCOLLIDE        = (1<<6),
    EF_DRAWOVER         = (1<<7)
};

/**
============================
Entity Types
============================
*/
enum EntTypes
{
    TYPE_BASE,
    TYPE_ORGANISM,
    TYPE_OBJECT,
    TYPE_WEAPON,
    TYPE_PLAYER,

    TYPE_UNKNOWN
};

/**
=================================
Entity interface
=================================
*/
class IEntity
{

public:
    IEntity();
    IEntity(const IEntity&);
    
    /** Apply Common Dictionary Attributes */
    virtual void Apply();
    /** This Ents unique ID */
    unsigned int  GetID() { return m_id; };
    /** Set this Ents ID */
    void SetID(unsigned int id) { m_id = id; };

    /** Get the Entity Type */
    virtual int GetType() { return TYPE_BASE; };
    
    /** This Ent is Active */
    bool IsActive() { return m_active; };
    /** Set activity */
    void SetActive(bool b) { m_active = b; };

    /** Get the face direction */
    int GetFace() { return m_face; };
    /** Set the direction */
    void SetFace( int f);

    /** Set the name */
    void SetName( const std::string &s) { m_name = s; };
    /** Get the name */
    std::string &GetName() { return m_name; };

    /** Set the active state */
    void SetState(const std::string &state) { m_FSM.ChangeState( m_states[state] ); };
    /** Get the current state */
    std::string GetState() { return m_FSM.GetCurrentState() ? m_FSM.GetCurrentState()->GetStateType() : "IDLE"; };

    /** Update the entity */
    virtual void Update( long dt);// { };

    /** Apply this ents trigger */
    virtual void Trigger() {};

    /** Set this ents trigger script */
    void SetTrigger( const std::string &filename) { 
        m_fileName = filename;
    };

    /** Collide with another entity */
    virtual bool CollideWith( IEntity* ent ) { return false; };

    /** Move this ent */
    virtual bool MoveTo( const Vector2f &dest ) { 
        //m_world = dest; 
        //m_position = dest;
        m_physObject.SetPosition( dest );
        m_flags |= EF_MOVED;

        UpdateCollisionBounds( (int)dest.x, (int)dest.y );
        return false; 
    };
    /** Move the entity */
    virtual void MoveToOverTime( const Vector2f &dest, float time ) {
        m_dest = dest;
        m_direction = dest;
        //m_velocity = dest;
        m_moveTime = time;
    };

    /** Arrived to location */
    bool ArrivedToLocation(); 
	/** Damage this entity */
	virtual int Damage( int hit );

    /** Kill this entity */
    virtual void Kill() { m_health = 0; };

    /** This entity is carrying something */
    void Carry( IEntity* ent ) {
        // Set the entities state to carrying
        SetState( ENT_STATES[CARRYING] );
        // set the other entity to being carried
        ent->SetState( ENT_STATES[CARRIED] );
        ent->Carrier( this );

        m_carriedEntity = ent; 
        
    };

    /** Carried By */
    void Carrier( IEntity* ent ) {
        m_carrier = ent;
    };
    /** Who is carrying this entity */
    IEntity* CarriedBy() { return m_carrier; };

    bool CarryingEntity() { return m_carriedEntity!=NULL; }
    /** Throws the entity */
    void Throw();

    /** Get the Reach rectangle - creates a rect infront of entity */
    Rect GetReachRectangle();

    /** Remove the ent */
    bool CanRemove() { return m_remove; };
    /** Set the remove flag */
    void SetRemove(bool r) { m_remove = r; };

    ///** Update the Position Coordinates */
    //void UpdateScreenCoord( const Vector2f &screenCoords );
    /** Update bounds */
    void UpdateCollisionBounds( int x, int y );
    /** Get the collision bounds */
    Rect GetBounds() { return m_bounds; };
    /** Update the entities bounds */
    void SetBounds(int x, int y, int width, int height) {   m_bounds.x = x; m_bounds.y = y; 
                                                            m_bounds.width = width; m_bounds.height = height;
                                                        };

    /** Add a state */
    void AddState(const std::string &state, State* s) {
        m_states[state] = s;
    };

    /** Test if this is a player */
    virtual bool IsPlayer() {return false;};

    /** Pick Up an Item */
    virtual void PickUpItem(IEntity* ent);
 
    // forward vector
    Vector2f        m_forward;
    // Direction
    Vector2f        m_direction;
    // Speed (should probably be a scalar)
    float           m_fSpeed;
    //// Position
    //Vector2f        m_position;
    //// Velocity to move too
    //Vector2f        m_velocity;
    //// Constant Velocity
    //Vector2f        m_baseVelocity;
    //// World coordinates
    //Vector2f        m_world;

    // Do translations 
    PhysicsObject   m_physObject;
    // health
	int				m_health;
    // flags
    int             m_flags;
    // height above ground
    float           m_heightAboveGround;
    // gravity
    float           m_gravity;
    
    /*-------------------------------------------
        TODO - Make all atrributes in the dictionary
    --------------------------------------------*/
    // Dictionary of attributes
    EntDict     m_attributes;

    // items inventory
    Inventory<IEntity*> m_itemInventory;
    // weapons inventory
    Inventory<IWeapon*> m_weaponInventory;

    // action received from the controller
    int             m_actions;

    // the entities next update
    float           m_nextUpdate;
    virtual ~IEntity();

protected:
    /** Dis/Enable user input */
    void EnableInput( bool b ) { m_readInput = b; };
    bool InputEnabled() { return m_readInput; };
    /** Check the face of the entity */
    void CheckFace(int action);

    // if this entity should
    // receive input
    bool               m_readInput;
    // id
    unsigned int             m_id;
    // activity
    bool            m_active;

    // Collision bound
    Rect            m_bounds;
    // Direction facing
    int             m_face;
    // old face
    int             m_oldFace;
    // entity being carried
    IEntity*        m_carriedEntity;
    // entity doing the carring
    IEntity*        m_carrier;
	
    // destination point
    Vector2f        m_dest;
    Vector2f        m_throwVel;
    float           m_moveTime;

    // Trigger file ~LUA script
    std::string     m_fileName;
    
    // name of entity
    std::string m_name;

    // remove flag
    bool            m_remove;

    // Entity controller - capture events
    EntityController    m_entCtrl;

    /*--------------------------------
        Finite State Machine
    ---------------------------------*/
    // FSM
    StateMachine m_FSM;
    // state list
	// -------WEIRD errors occur when I use the typedef
    typedef std::map<std::string , State*> type_States;
    type_States m_states;

    // friends
    friend State;
    friend EntityController;

};
